package com.binest.util;

import co.elastic.clients.elasticsearch.ElasticsearchClient;

import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.elasticsearch.core.DeleteResponse;
import co.elastic.clients.elasticsearch.core.GetResponse;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;


import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.transport.endpoints.BooleanResponse;

import com.binest.common.utils.StringUtils;
import com.binest.vo.DocumentPartESDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class ElasticsearchHandle {


    private static ElasticsearchClient client;


    @Resource(name="clientByPasswd")
    public  void setClient(ElasticsearchClient client) {
        ElasticsearchHandle.client = client;
    }

    /**
     * 判断索引是否存在
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean hasIndex(String indexName) throws IOException {
        BooleanResponse exists = client.indices().exists(d -> d.index(indexName));
        return exists.value();
    }

    /**
     * 删除索引
     *
     * @param indexName
     * @throws IOException
     */
    public boolean deleteIndex(String indexName) throws IOException {
        DeleteIndexResponse response = client.indices().delete(d -> d.index(indexName));
        return true;
    }

    /**
     * 创建索引
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean createIndex(String indexName) throws Exception {
        try {
            CreateIndexResponse indexResponse = client.indices().create(c -> c.index(indexName));
        } catch (IOException e) {
            log.error("索引创建失败：{}", e.getMessage());
            throw new Exception("创建索引失败");

        }
        return true;
    }

    /**
     * 创建索引，不允许外部直接调用
     *
     * @param indexName
     * @param mapping
     * @throws IOException
     */
    private boolean createIndex(String indexName, Map<String, Property> mapping) throws IOException {
        CreateIndexResponse createIndexResponse = client.indices().create(c -> {
            c.index(indexName).mappings(mappings -> mappings.properties(mapping));
            return c;
        });
        return createIndexResponse.acknowledged();
    }



    /**
     * 重新创建索引,如果已存在先删除
     *
     * @param indexName
     * @param mapping
     */
    public void reCreateIndex(String indexName, Map<String, Property> mapping) throws Exception {
        try {
            if (this.hasIndex(indexName)) {
                this.deleteIndex(indexName);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("删除索引失败");
        }

        try {
            this.createIndex(indexName, mapping);
        } catch (IOException e) {
            e.printStackTrace();
            throw new Exception("重新创建索引失败");

        }
    }


    /**
     * 新增数据
     *
     * @param indexName
     * @throws IOException
     */
    public static boolean insertDocument(String indexName, Object obj, String id) throws Exception {
        try {
            IndexResponse indexResponse = client.index(i -> i
                    .index(indexName)
                    .id(id)
                    .document(obj));
            return true;
        } catch (IOException e) {
            log.error("数据插入ES异常：{}", e.getMessage());
            throw new Exception("ES新增数据失败");
        }
    }

    /**
     * 查询数据
     *
     * @param indexName
     * @param id
     * @return
     */
    public static GetResponse<DocumentPartESDto> searchDocument(String indexName, String id) throws Exception {

        try {
            GetResponse<DocumentPartESDto> getResponse = client.get(g -> g
                            .index(indexName)
                            .id(id)
                    , DocumentPartESDto.class
            );
            return getResponse;
        } catch (IOException e) {
            log.error("查询ES异常：{}", e.getMessage());
            throw new Exception("查询ES数据失败");

        }
    }

    /**
     * 删除数据
     *
     * @param indexName
     * @param id
     * @return
     */
    public  static boolean deleteDocument(String indexName, String id) throws Exception {
        try {
            DeleteResponse deleteResponse = client.delete(d -> d
                    .index(indexName)
                    .id(id)
            );
        } catch (IOException e) {
            log.error("删除Es数据异常：{}", e.getMessage());
            throw new Exception("数据删除失败");
        }
        return true;
    }




    /**
     * match查询语句.
     *
     * @param fieldName 查询字段名称
     * @param fieldValue 查询字段值
     * @return query语句
     */
    public static Query initMatchQuery(String fieldName, String fieldValue) {
        return StringUtils.isNotBlank(fieldValue) ? MatchQuery.of(m -> m
                .field(fieldName + ".keyword")
                .query(fieldValue)
        )._toQuery() : null;
    }

    /**
     * range查询语句.
     *
     * @param fieldName 查询字段名称
     * @param begin 开始时间
     * @param end 结束时间
     * @return query语句
     */

    public static Query initRangeQuery(String fieldName, Integer begin, Integer end) {
        return  RangeQuery.of(m -> m
                .field(fieldName + ".keyword")
                .gte((JsonData.of(begin)))
                .lte((JsonData.of(end)))
        )._toQuery();
    }










}
